﻿namespace HashMaster.Agent.Neo
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using HashMaster.Lib;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class HashProcess
    {
        ///程序所在目录
        //string path = Utility.HashcatPath;
        //string path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

        Process p;
        ///进程状态
        EnumStatus Status;
        /////任务参数
        //ClientSyncData job;


        /// <summary>
        /// 当状态变化后抛出事件
        /// 任务开始、低效、完成
        /// </summary>
        /// <param name="status"></param>
        public delegate void StatusChangeddHandle(EnumStatus status);
        public event StatusChangeddHandle StatusChanged;


        public HashProcess() 
        {
            Status = EnumStatus.Pending;

        }


        /// <summary>
        /// 启动一个任务，只有当这个对象pendding状态才能这么做
        /// </summary>
        /// <param name="jobData"></param>
        /// <returns></returns>
        public bool StartJob(ClientSyncData jobData)
        {
            //进程正在运行 取消新进程的开启
            if (Status == EnumStatus.Started) return false;


            p = new Process
                {
                    StartInfo = new ProcessStartInfo()
                        {
                            WorkingDirectory = Utility.HashcatPath,
                            FileName = Utility.HashcatPath + @"\cudaHashcat-lite32.exe",
                            Arguments = BuildArguments(jobData),
                            //Arguments = string.Format(@"{0}:{1} -1 00010203040506070809 -m 1900 {2} --gpu-accel 160 --gpu-watchdog=0 --outfile-watch={3} --session={4} --restore-timer={3} --outfile=d:\{4}", jobData.Sha, jobData.Imei, GetMaskString(jobData), Utility.MonitorInterval.ToString(), jobData.JobId),
                            UseShellExecute = false,
                            Verb = "runas",
                            // RedirectStandardError=true,
                            //RedirectStandardInput=true,
                            //RedirectStandardOutput=true,
                        }
                };
#if RELEASE
            p.StartInfo = new ProcessStartInfo()
            {
                WorkingDirectory=Utility.HashcatPath,
                FileName = Utility.HashcatPath + @"\cudaHashcat-lite32.exe",
                Arguments=BuildArguments(jobData),
                //Arguments = string.Format("{0}:{1} -1 00010203040506070809 -m 1900 {2} --gpu-accel 1 --gpu-watchdog=0 --outfile-watch={3} --session={4} --restore-timer={3} --outfile=d:\\{4}", jobData.Sha, jobData.Imei,BuildArguments(jobData),Utility.MonitorInterval.ToString(),jobData.JobId),
                UseShellExecute = false,
                Verb="runas",
                //RedirectStandardError = true,
                //RedirectStandardInput = true,
                //RedirectStandardOutput = true,
            };
#else
#endif
            //显示完整参数
            //Console.WriteLine("\r\n\r\n"+p.StartInfo.Arguments);

            //注册事件
            p.Exited += new EventHandler(p_Exited);
            p.EnableRaisingEvents = true;
            
            

            //启动进程
            p.Start();
            p.PriorityClass = Utility.HashcatPriority;
            Console.WriteLine("Run Hashcat at " + p.PriorityClass.ToString());

            /////创建watcher监视restore文件
            //Program.watcher = new FileSystemWatcher();
            //Program.watcher.Path = Utility.HashcatPath;
            //Program.watcher.NotifyFilter = NotifyFilters.CreationTime;
            //Program.watcher.Filter = Utility.ClientData.JobId.ToString() + ".restore";
            //Program.watcher.Changed += new FileSystemEventHandler(Program.watcher_Changed);
            //Program.watcher.EnableRaisingEvents = true;

            //标记进程为开始状态，此状态无法再启动进程
            Status = EnumStatus.Started;
            StatusChanged(Status);


            return true;
        }

        public void EndCurrentJob()
        {
            try
            {
                p.Kill();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message); 
             //   throw;
            }
            
           
        }

        /// <summary>
        /// 进程终止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void p_Exited(object sender, EventArgs e)
        {
            //进程正常终止
            Status = p.ExitCode==0 ? EnumStatus.Finished : EnumStatus.Pending;
            CheckResult();
            StatusChanged(Status);
        }

        void CheckResult()
        {
            if (File.Exists(@"d:\" +Utility.ClientData.JobId))
            {
                Utility.ClientData.Result = File.ReadAllText(@"d:\" + Utility.ClientData.JobId);
                Utility.ClientData.Progress = 100;
                Console.WriteLine(">>Found Result!!!");
            }
        }

        /// <summary>
        /// 补完mask
        /// </summary>
        /// <param name="job"></param>
        /// <returns></returns>
        private string GetMaskString(ClientSyncData job)
        {
            string ret;
            ret = string.Concat(Enumerable.Repeat("?1", 15 - job.SliceWidth));

            for (int i = 0; i < job.SliceWidth - job.SliceNum.ToString().Length; i++)
            {

                ret += "00";
            }

            for (int i = 0; i < job.SliceNum.ToString().Length; i++)
            {
                ret += "0" + job.SliceNum.ToString().Substring(i, 1);
                //ret += "0" + ((int)(job.SliceNum % Math.Pow(10, i + 1) / Math.Pow(10, i))).ToString();
            }
            return ret;

        }

        public string BuildArguments(ClientSyncData job) 
        {
            string[] Mask = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09" };
            int SlicePrefix = job.SliceNum >= 100 ? int.Parse(job.SliceNum.ToString().Substring(0,1)) : 0;
            string MaskArgument = string.Empty;
            string MaskString = string.Empty;
            string ret= string.Empty;

            /*
             * 格式备注
             * 
             * Job.SliceWidth=5
             * Job.SliceNum=102
             *  -> SlicePrefix=1 
             *
             * * -2 0001  <--MaskArgument
             * 
             * ?1?1?1?1?1?1?1?1?1?1?1?1?20002
             *    
             * 
             */

            MaskArgument += Mask[SlicePrefix * 2] + Mask[SlicePrefix * 2 + 1];

            //for (int i = SlicePrefix*(10/job.SliceWidth); i < 10/job.SliceWidth; i++)
            //{
            //    MaskArgument += Mask[i];
            //}
            MaskString += "?2";

            if (job.SliceNum < 10)
            {
                MaskString += "00";
            }

            for (int i = MaskArgument.Length+2; i < 30; i+=2)
            {
                MaskString = "?1" + MaskString;//?1
            }



            for (int i = (job.SliceNum>=100?1:0); i < job.SliceNum.ToString().Length; i++)
            {
                MaskString += "0" + job.SliceNum.ToString().Substring(i, 1);
                //ret += "0" + ((int)(job.SliceNum % Math.Pow(10, i + 1) / Math.Pow(10, i))).ToString();
            }

#if RELEASE
            ret = string.Format(
                "{0}:{1} -1 00010203040506070809 -2 {2} -m 1900 {3} --gpu-accel 1 --gpu-watchdog=0 --outfile-watch={4} --session={5} --restore-timer={4} --outfile=d:\\{5}",
                job.Sha, "00"+job.Imei.Substring(0,14)+"00",MaskArgument,MaskString, Utility.MonitorInterval.ToString(), job.JobId);
#else
            ret = string.Format(
                "{0}:{1} -1 00010203040506070809 -2 {2} -m 1900 {3} --gpu-accel 160 --gpu-watchdog=0 --outfile-watch={4} --session={5} --restore-timer={4} --outfile=d:\\{5}",
                job.Sha,  "00"+job.Imei.Substring(0,14)+"00",MaskArgument,MaskString, Utility.MonitorInterval.ToString(), job.JobId);
#endif


            return ret;
        }
    }
}
